using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Web;

namespace Seaskyer.WebApp.Utility.BigUpload
{
    internal class RequestStream
    {
        #region Fields

        private ArrayList contentBody;
        private FileStatus fileStatus;
        private FileStream fs;
        private ArrayList readBody;
        private ReadStatus readStatus;
        private string originalFileName;

        #endregion

        // Nested Types
        public enum FileStatus : byte
        {
            // Fields
            Close = 1,
            Open = 0
        }

        public enum ReadStatus : byte
        {
            // Fields
            NoRead = 0,
            Read = 1
        }

        #region Properties

        public ArrayList ContentBody
        {
            get { return this.contentBody; }
        }

        public FileStream FileStream
        {
            get { return this.fs; }
        }

        public FileStatus FStatus
        {
            get { return this.fileStatus; }
        }

        public string OriginalFileName
        {
            get { return this.originalFileName; }
        }

        public ArrayList ReadBody
        {
            get { return this.readBody; }
        }

        public ReadStatus RStatus
        {
            get { return this.readStatus; }
        }

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="preloadBytes"></param>
        /// <param name="boundaryBytes"></param>
        /// <param name="fileStream"></param>
        /// <param name="fileStatus"></param>
        /// <param name="readStatus"></param>
        /// <param name="uploadFolder"></param>
        /// <param name="writeToDisk"></param>
        /// <param name="context"></param>
        /// <param name="currFileName"></param>
        public RequestStream(byte[] preloadBytes, byte[] boundaryBytes, FileStream fileStream,
            FileStatus fileStatus, ReadStatus readStatus, string uploadFolder, bool writeToDisk,
            HttpContext context, string currFileName)
        {
            this.readBody = new ArrayList();
            this.contentBody = new ArrayList();
            this.fs = null;
            this.originalFileName = string.Empty;
            this.fileStatus = FileStatus.Close;
            this.readStatus = ReadStatus.NoRead;
            this.originalFileName = currFileName;
            this.fs = fileStream;
            this.fileStatus = fileStatus;
            this.readStatus = readStatus;

            int preloadPosition = 0;
            while ((preloadPosition < preloadBytes.Length))
            {
                ArrayList list1 = new ArrayList();

                //If char is \n
                if (preloadBytes[preloadPosition] == 13)
                {
                    int boundaryPosition = 0;
                    while (((preloadPosition < preloadBytes.Length) && (boundaryPosition < boundaryBytes.Length)))
                    {
                        if (preloadBytes[preloadPosition] != boundaryBytes[boundaryPosition])
                        {
                            break;
                        }

                        list1.Add(preloadBytes[preloadPosition]);

                        boundaryPosition++;
                        preloadPosition++;
                    }

                    if (boundaryPosition == boundaryBytes.Length)
                    {
                        if (this.fileStatus == FileStatus.Open)
                        {
                            this.fs.Flush();
                            this.fs.Close();
                            this.fileStatus = FileStatus.Close;
                            this.originalFileName = string.Empty;
                        }
                        else if (this.readStatus == ReadStatus.NoRead)
                        {
                            this.readStatus = ReadStatus.Read;
                            context.Items["Sunrise_Web_Upload_FileStatus"] = this.fileStatus;
                        }

                        if ((preloadPosition + 2) < preloadBytes.Length)
                        {
                            list1.Add(preloadBytes[preloadPosition]);
                            preloadPosition++;
                            list1.Add(preloadBytes[preloadPosition]);
                            preloadPosition++;

                            ArrayList list2 = new ArrayList();
                            while ((preloadPosition < preloadBytes.Length))
                            {
                                list1.Add(preloadBytes[preloadPosition]);

                                if (preloadBytes[preloadPosition] == 13)
                                {
                                    byte[] buffer = new byte[list2.Count];
                                    list2.CopyTo(buffer);

                                    //Get request content from buffer
                                    string requestContent = Utils.GetContext().Request.ContentEncoding.GetString(buffer);

                                    //If this line is content head
                                    if (requestContent.IndexOf("\"; filename=\"") > 0)
                                    {
                                        preloadPosition++;

                                        ArrayList list3 = new ArrayList();

                                        while ((preloadPosition < preloadBytes.Length))
                                        {
                                            list1.Add(preloadBytes[preloadPosition]);
                                            if (preloadBytes[preloadPosition] == 13)
                                            {
                                                if ((preloadPosition + 3) < preloadBytes.Length)
                                                {
                                                    char[] spliter = new char[1] { ';' };
                                                    string[] contentArray = requestContent.Split(spliter);

                                                    string fileNameString = contentArray[2].Trim();
                                                    fileNameString = fileNameString.Substring(10, (fileNameString.Length - 11));

                                                    if ((writeToDisk && (fileNameString != null)) && (fileNameString != string.Empty))
                                                    {
                                                        this.originalFileName = Path.GetFileName(fileNameString);
                                                        preloadPosition += 3;

                                                        byte[] buffer2 = new byte[list3.Count];
                                                        list3.CopyTo(buffer2);

                                                        string contentType = Utils.GetContext().Request.ContentEncoding.GetString(buffer2);

                                                        string guidFileName = (Guid.NewGuid().ToString() + Path.GetExtension(fileNameString));
                                                        string fileFullPath = uploadFolder;

                                                        //If upload folder deos not exist, use system temporary folder to hold the file.
                                                        if (fileFullPath == string.Empty)
                                                        {
                                                            fileFullPath = Path.GetTempPath();
                                                        }

                                                        fileFullPath = Path.Combine(fileFullPath, guidFileName);

                                                        //Build the content head
                                                        StringBuilder sb = new StringBuilder();
                                                        string[] sbArray = new string[11];

                                                        sbArray[0] = "\r\n";
                                                        sbArray[1] = contentArray[0];
                                                        sbArray[2] = ";";
                                                        sbArray[3] = contentArray[1];
                                                        sbArray[4] = "\r\n\r\n";
                                                        sbArray[5] = contentType.Trim();
                                                        sbArray[6] = ";filename=\"";
                                                        sbArray[7] = fileNameString;
                                                        sbArray[8] = "\";filepath=\"";
                                                        sbArray[9] = guidFileName;
                                                        sbArray[10] = "\"";
                                                        sb.Append(string.Concat(sbArray));

                                                        //Save boundary bytes to server file
                                                        this.fs = new FileStream(fileFullPath, FileMode.Create);
                                                        context.Items["Sunrise_Web_Upload_FileStream"] = this.fs;
                                                        this.fileStatus = FileStatus.Open;

                                                        context.Items["Sunrise_Web_Upload_FileStatus"] = this.fileStatus;
                                                        Hashtable ht = ((Hashtable)context.Items["Sunrise_Web_Upload_FileList"]);
                                                        ht.Add(Path.GetFileNameWithoutExtension(guidFileName), fileFullPath);
                                                        context.Items["Sunrise_Web_Upload_FileList"] = ht;

                                                        this.readBody.AddRange(boundaryBytes);
                                                        this.readBody.AddRange(Encoding.UTF8.GetBytes(sb.ToString().ToCharArray()));

                                                        sb.Remove(0, sb.Length);

                                                        break;
                                                    }

                                                    preloadPosition++;
                                                    break;
                                                }

                                                this.contentBody.AddRange(list1);
                                                break;
                                            }

                                            list3.Add(preloadBytes[preloadPosition]);
                                            preloadPosition++;
                                        }

                                        break;
                                    }

                                    this.readStatus = ReadStatus.NoRead;
                                    this.readBody.AddRange(list1);
                                    break;
                                }

                                list2.Add(preloadBytes[preloadPosition]);
                                preloadPosition++;
                            }
                            if (preloadPosition < preloadBytes.Length)
                            {
                                preloadPosition++;
                                continue;
                            }

                            this.contentBody.AddRange(list1);
                            preloadPosition++;
                            continue;

                            /*
                            if ((preloadBytes[preloadPosition] != 0x2d) || ((preloadPosition + 3) >= preloadBytes.Length))
                            {
                                preloadPosition++;
                                continue;
                            }
                            this.readBody.AddRange(boundaryBytes);
                            byte[] buffer3 = new byte[4] {0x2d, 0x2d, 13, 10};
                            this.readBody.AddRange(buffer3);
                            return;
                            */
                        }

                        this.contentBody.AddRange(list1);
                    }
                    else if (preloadPosition < preloadBytes.Length)
                    {
                        if (this.fileStatus == FileStatus.Open)
                        {
                            byte[] buffer4 = new byte[list1.Count];
                            for (int i = 0; i < list1.Count; i++)
                            {
                                buffer4[i] = ((byte)list1[i]);
                            }

                            this.fs.Write(buffer4, 0, buffer4.Length);
                        }
                        else if (this.readStatus == ReadStatus.NoRead)
                        {
                            this.readBody.AddRange(list1);
                        }

                        preloadPosition--;
                    }
                    else
                    {
                        this.contentBody.AddRange(list1);
                    }
                }
                else if (this.fileStatus == FileStatus.Open)
                {
                    this.fs.WriteByte(preloadBytes[preloadPosition]);
                }
                else if (this.readStatus == ReadStatus.NoRead)
                {
                    this.readBody.Add(preloadBytes[preloadPosition]);
                }

                preloadPosition++;
            }
        }

        /// <summary>
        /// Destructor method, release all resource
        /// </summary>
        ~RequestStream()
        {
            this.readBody = null;
            this.contentBody = null;
            this.fs = null;
        }
    }
}